package generateConnections;

import java.util.ArrayList;

import exception.NoConnectionPossibleException;

import logging.Logger;

import networkInterface.NetworkInterfaceBase;

import object.Node;
import util.NodeUtil;

//This connection algorithm will add nodes to the network using a 
// set proportion of it's connections. This will leave interfaces open
// for new nodes to connect to the network
public class GenerateLimitedConnections extends GenerateConnectionBase {

	
	@Override
	public void genConnections(ArrayList<Node> nodes, Node connectingNode) {
		
		double threshold = .66;		
		
		int numConnections = 0;
		for( NetworkInterfaceBase connectingInterface : connectingNode.getInterfaces() )
		{
			//Get the number of connections that node has available
			numConnections += connectingInterface.getNumberOfConnections();
		}
		Logger.getInstance().log(Logger.TRACE, "In limited connections: interface can have " + numConnections + " connections");
		
		if( numConnections == 0 )
			return;
		
		
		
		ArrayList<Node> connected = new ArrayList<Node>();
		ArrayList<Node> junk = new ArrayList<Node>();
		while( connectingNode.getConnections().size() == 0 || (double)connectingNode.getConnections().size()/numConnections <= threshold )
		{
			Logger.getInstance().log(Logger.TRACE, "In the loop");
			//find largest network to connect to
			int largest = 0;
			NetworkInterfaceBase bestTarget = null;
			NetworkInterfaceBase connectingInterface = null;
			for( NetworkInterfaceBase connInterface : connectingNode.getInterfaces() )
			{	
				//If the interface has no available connections, go to the next interface
				if( !connInterface.hasConnectionsAvailible() )
					continue;
				
				//loop through the target interfaces to find the one connected to the largest network
				for( NetworkInterfaceBase target : connInterface.getConnectableInterfaces(nodes) )
				{
					//If that node is already connected into the network, continue to the next target
					if( connected.contains(target.getNode()) )
						continue;
					if( largest == 0 || largest < NodeUtil.mapNetwork(target.getNode(), junk) )
					{
						largest = NodeUtil.mapNetwork(target.getNode(), junk);
						bestTarget = target;
						connectingInterface = connInterface;
					}
				}
			}
			
			if( largest == 0 )
			{
				for( NetworkInterfaceBase conInterface : connectingNode.getInterfaces() )
				{
					if( conInterface.getConnectableInterfaces(nodes).size() != 0 )
					{
						connectingInterface = conInterface;
						bestTarget = conInterface.getConnectableInterfaces(nodes).get(0);
					}
				}
			}
			if( connectingInterface == null || bestTarget == null )
			{
				Logger.getInstance().log(Logger.WARNING, "No interface to connect to");
				return;
			}
			else
			{
				Logger.getInstance().log(Logger.TRACE, "Attempting to create a connection");
				try {
					connectingInterface.addConnection(bestTarget);
				} catch (IllegalStateException e) {
					Logger.getInstance().log(Logger.WARNING, "Reached an unpleasant state while attempting to create a connection");
				} catch (NoConnectionPossibleException e) {
					Logger.getInstance().log(Logger.WARNING, "Could not create a connection to the target interface");
				}
			}
			
			NodeUtil.mapNetwork(connectingNode, connected);
		}
		
	}

}
